package com.softao.ming.gde.internal.core.model;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import com.softao.ming.gde.core.model.IBundleBuildFile;
import com.softao.ming.gde.core.model.IBundleGwtPluginFile;
import com.softao.ming.gde.core.model.IBundleManifestFile;
import com.softao.ming.gde.core.model.IBundleModel;
import com.softao.ming.gde.core.model.IBundleModelKey;
import com.softao.ming.gde.core.model.IBundlePluginFile;
import com.softao.ming.gde.core.model.IBundleVersion;

/**
 * Retrieves bundle information.
 */
public class BundleModelImpl implements IBundleModel {
	static class BundleModelKeyImpl implements IBundleModelKey {
		private final IBundleModel mBundle;

		public BundleModelKeyImpl(IBundleModel bundle) {
			mBundle = bundle;
		}
		
		@Override
		public String getUniqueIdentifier() {
			return mBundle.getManifestFile().getBundleUniqueIdentifier();
		}

		@Override
		public IBundleVersion getVersion() {
			return mBundle.getManifestFile().getBundleVersion();
		}

		@Override
		public boolean isSourceBundle() {
			return mBundle.getManifestFile().isSourceBundle();
		}

		@Override
		public boolean equals(Object arg0) {
			if (arg0 == null || !(arg0 instanceof IBundleModelKey)) {
				return false;
			}
			IBundleModelKey key = (IBundleModelKey)arg0;
			return key.getUniqueIdentifier().equals(this.getUniqueIdentifier())
				&& key.getVersion().equals(this.getVersion())
				&& key.isSourceBundle() == this.isSourceBundle();
		}
		
		@Override
		public String toString() {
			return getUniqueIdentifier() + "@" + getVersion() + "@" + isSourceBundle();
		}
		
		@Override
		public int hashCode() {
			return toString().hashCode();
		}
		
		@Override
		public int compareTo(IBundleModelKey bundle) {
			int result = getUniqueIdentifier().compareTo(bundle.getUniqueIdentifier());
			if (result != 0) {
				result = getVersion().compareTo(bundle.getVersion());
			}
			if (result != 0) {
				result = isSourceBundle() 
						? (bundle.isSourceBundle() ? 0 : 1) 
						: (bundle.isSourceBundle() ? 1 : 0);
			}
			return result;
		}
		
	}
	
	/** */
	private static final String FILE_MANIFEST_MF = "META-INF/MANIFEST.MF";
	/** */
	private static final String FILE_GWT_PLUGIN_XML = "gwt.plugin.xml";
	/** */
	private static final String FILE_PLUGIN_XML = "plugin.xml";
	/** */
	private static final String FILE_DOT_PROJECT = ".project";
	/** */
	private static final String FILE_BUILD_PROPERTIES = "build.properties";
	
	private final BundlePluginImpl mBundlePlugin;
	private final BundleManifestFileImpl mBundleManifest;
	private final BundleGwtPluginFileImpl mBundleGwtPlugin;
	private final BundleBuildFileImpl mBundleBuild;
	private final File mFile;
	private final boolean mIsGdeProject;
	
	/**
	 * @param file the root path of the plugin directory or the jar file
	 * 
	 * TODO: Folder plug-in not project...
	 * @throws IOException 
	 */
	public BundleModelImpl(File file) throws IOException {
		mFile = file;
		
		boolean isGdeProject = false;
		BundlePluginImpl bundlePlugin = null;
		BundleManifestFileImpl bundleManifest = null;
		BundleGwtPluginFileImpl bundleGwtPlugin = null;
		BundleBuildFileImpl bundleBuild = null;
		
		if (file.isDirectory()) {
			File tempFile = new File(file, FILE_BUILD_PROPERTIES);
			if (tempFile.exists()) {
				InputStream inputStream = new FileInputStream(tempFile);
				try {
					bundleBuild = new BundleBuildFileImpl(inputStream);
				} finally {
					inputStream.close();
				}
			}
			
			tempFile = new File(file, FILE_DOT_PROJECT);
			if (tempFile.exists()) {
				isGdeProject = true;
			}
			tempFile = new File(file, FILE_PLUGIN_XML);
			if (tempFile.exists()) {
				InputStream inputStream = new FileInputStream(tempFile);
				try {
					bundlePlugin = new BundlePluginImpl(inputStream);
				} finally {
					inputStream.close();
				}
			}
			
			tempFile = new File(file, FILE_GWT_PLUGIN_XML);
			if (tempFile.exists()) {
				InputStream inputStream = new FileInputStream(tempFile);
				try {
					bundleGwtPlugin = new BundleGwtPluginFileImpl(inputStream);
				} finally {
					inputStream.close();
				}
			}
			
			tempFile = new File(file, FILE_MANIFEST_MF);
			if (tempFile.exists()) {
				InputStream inputStream = new FileInputStream(tempFile);
				try {
					bundleManifest = new BundleManifestFileImpl(inputStream);
				} finally {
					inputStream.close();
				}
			}
		} else {
			ZipFile zipFile = new ZipFile(file);
			Enumeration<? extends ZipEntry> entries = zipFile.entries();
			while (entries.hasMoreElements()) {
				ZipEntry zipEntry = entries.nextElement();
				if (zipEntry.isDirectory()) {
					continue;
				}
				
				String name = zipEntry.getName();
				if (FILE_PLUGIN_XML.equals(name)) {
					InputStream inputStream = zipFile.getInputStream(zipEntry);
					try {
						bundlePlugin = new BundlePluginImpl(inputStream);
					} finally {
						inputStream.close();
					}
				} else if (FILE_DOT_PROJECT.equals(name)) {
					isGdeProject = true;
				} else if (FILE_MANIFEST_MF.equals(name)) {
					InputStream inputStream = zipFile.getInputStream(zipEntry);
					try {
						bundleManifest = new BundleManifestFileImpl(inputStream);
					} finally {
						inputStream.close();
					}
				} else if (FILE_GWT_PLUGIN_XML.equals(name)) {
					InputStream inputStream = zipFile.getInputStream(zipEntry);
					try {
						bundleGwtPlugin = new BundleGwtPluginFileImpl(inputStream);
					} finally {
						inputStream.close();
					}
				} else if (FILE_BUILD_PROPERTIES.equals(name)) {
					InputStream inputStream = zipFile.getInputStream(zipEntry);
					try {
						bundleBuild = new BundleBuildFileImpl(inputStream);
					} finally {
						inputStream.close();
					}
				}
			}
		}
		
		mIsGdeProject = isGdeProject;
		mBundleBuild = bundleBuild;
		mBundleGwtPlugin = bundleGwtPlugin;
		mBundleManifest = bundleManifest;
		mBundlePlugin = bundlePlugin;
	}
	
	@Override
	public IBundleBuildFile getBuildFile() {
		return mBundleBuild;
	}

	@Override
	public IBundleGwtPluginFile getGwtPluginFile() {
		return mBundleGwtPlugin;
	}

	@Override
	public IBundleManifestFile getManifestFile() {
		return mBundleManifest;
	}

	@Override
	public IBundlePluginFile getPluginFile() {
		return mBundlePlugin;
	}

	@Override
	public IBundleModelKey getKey() {
		return new BundleModelKeyImpl(this);
	}

	@Override
	public File getContainerFile() {
		return mFile;
	}
	
	@Override
	public boolean isGdeProject() {
		return mIsGdeProject;
	}
}
